Welcome back to continue scripting our game and to actually start seeing some of the functionality of
our main GUI.
We should start to script the game handler that is inside of our starter player scripts.
This module script is going to be responsible for listening to when new sections of the game start,
and for animating the player's camera to its respective cut scenes.
So it's going to listen to our game comms event, and it's going to execute code specifically for starting,
like the introduction scene of our game and like the stair scene of our game.
The service will also be responsible for disabling the reset button for our player.
So let's go ahead and open this up.
And inside of here we're only going to need two services replicated storage.
And then we're also going to need the starter guy.
And then we need to create the variable to represent this module script.
So we'll call it game handler.
And we'll make sure to return it at the very end of our script.
Now I'm going to also create a reference to the folder that contains all of the modules on the client.
So in our starter player scripts we have this folder called modules.
And we have a module script in here called Game Scenes.
And this is going to store the code that we need to execute for, you know the different scenes like
the intro scene, the stairs scene and stuff like that.
So we can reference that section in our code by either grabbing the local player going into their player
scripts folder and getting the modules folder that way.
Or we can also get the modules folder by simply referencing the script itself, getting the parent of
the script which would be the handlers folder, and then getting the parent of this folder, which would
be the client.
And then from that point we can grab our modules folder.
After this point, we're going to make a reference to our game comms event which is in replicated storage,
dot events, dot remotes, dot game communication.
And then we're also going to get the game comms enum.
So we'll require this from updated storage dot modules dot enums dot game communication enum.
And then we're going to go ahead and also require our game scenes module script.
So inside of here I'm just going to create a quick table.
We'll just call it game scenes.
And we'll make sure to return it at the end here as well.
And then in here we'll just make a reference to it.
We'll just call it scenes and we'll require it from our modules folder.
Dot game scenes.
Now inside of here we're going to need a function for initializing the game handler.
And we're also going to need a function for starting our game handler.
So inside of our initialize section, all we need to do is listen to our games comms event on client
event, and we can go ahead and connect a private function for this.
So we can create a private function in here.
And we'll call it on game comms event.
We get passed an action and arguments for that action.
And we'll connect to this function to our game comms event.
And inside of here, all we need to check is if the action is equal to the game.
Comms enum dot two client dot start intro scene.
If we're going to start the intro scene, then we're going to execute a function within our scenes module
script.
Otherwise, if the action is let's say game comms enum dot two client dot start stair scene, then we're
going to do that other scene as well.
And then inside of the start function for our game handler, all we're going to do is reference our
started UI and use the set core function to disable the reset button callback.
That way our players are unable to use the reset button, and we do not have to use a p call on this
function, because this module script is only going to run after the game has loaded.
So all of our core scripts should be available and ready to go.
And we don't have to wrap this function here in a P call.
So when we are given, for example, a command or action to start the intro scene, we could reference
our scenes module script and we could have a function in there like start intro scene and pass the arguments
along with it to, you know, start the intro scene.
And then we could also do the same thing for the star scene.
We could just name this function start Star scene.
So let's go ahead and go into our game scenes module script.
And inside of here we're going to need a few services.
We're of course going to need replicated storage.
We're going to need the tween service.
We are going to need the run service.
We will need the player service.
And I believe that's all of the services we'll need in here for now.
So some variables we're going to have to make.
First off is a reference to the local player.
So player's dot local player.
We're going to make a reference to a different uh bindable event in replicated storage.
And this is called uh update Guy.
But it's a bindable event so we can call it Guy bind event.
It's in replicated storage, dot events, dot Bindesboll's dot update guy.
And we're going to use this Bindable event to communicate to our, uh, main guy handler to, uh, do
different actions.
For example, uh, doing something like the intro message to display on the screen when the game starts.
And since we're going to be using this event, we should also grab our GUI actions enum from upper storage
as well.
So module dot enums dot gui actions enum.
Then we're going to make a reference to the current camera in the workspace.
So workspace dot current camera.
And then we're also going to have to make a reference to our filtering folder in the workspace.
Because there are some invisible parts in there that we need to tween something to.
And you'll see what that is in a moment.
And I'm also going to be creating a new random data type.
Now, the two functions we're going to need in here for now is one to start our intro scene.
And if you remember, we get past arguments to this function.
And we're also going to need a function to start the stair scene.
And we get past arguments to that as well.
Now when this module script gets told to start the introduction scene, what we need to first do is
reference our GUI Bindable event and fire to our main GUI handler that we wish to do an action of the
intro message.
So we want to start up our intro message.
So that means if we go back to our main GUI handler, we need to create a section for handling that
Bindable event.
So inside of our variable section we can make a reference to it real quick.
We'll just call it update GUI bind event and that's in replicated storage dot events dot binding bulls
dot update GUI.
And then what we could do is we could go ahead and scroll down to our initialize function.
Here we are.
And we can go ahead and add a section to listening to this event.
So we can refer to our update Guy Bindable event and listen for when it gets fired.
We'll get the action for this event and argument supplied to the action.
And the only action we are going to listen for in here is our intro message action.
So if the action is equal to GUI actions enum dot intro message, then all we're going to do is we're
going to first make sure inside of our message frame that the text label in there has no current text.
So we're going to set it to be blank.
And then we're going to set the message frame dot visibility equal to true.
And then we're going to use our display intro message function and pass inside of the messages table
our action.
Because remember inside of the messages table for our particular intro message action, we have three
different messages we need to display onto the screen.
We also need to pass a delay between the messages.
Now of course we could hard code it in here, or we could give our game scenes module script control
over how many seconds we want to wait between each of the messages, so we could pass a table here and
inside create a key for something like delay.
Between messages and we could set it to something like four seconds.
And since we're going to be getting this key passed to our ARGs table, we can just go ahead and pass
args dot delay between messages.
So now when we go ahead and call this function it's going to display our message frame on the screen.
And it's going to set the text in there to each of the different texts inside of the table that was
passed to the function plays the sound, and then eventually, after it passes through all the messages,
it fades out our message frame.
All right.
So then the next thing that we could do inside of our start intro stream function is that we want to
refer to our current camera, and we want to set the camera type equal to the enum dot camera TypeScript
label.
And then we want to set the current camera's dot frame equal to a new position.
And that new position is going to be inside of our bus.
So if we go on the map here and looks like I went the wrong direction, let me let me try to find the
bus somewhere.
Our bus should be around here somewhere.
Oh, I saw it.
There it is.
So we need to set our camera c frame to this invisible part.
And then we need to tween this bus along the road and have our camera continually update and follow
the position of this part.
So inside of here we could also create a reference to the bus itself.
We'll create a variable in this function.
We'll just call it bus.
And that's going to be equal to the workspace dot outdoor folder dot bus.
Then we can reference our bus.
And inside of the bus there's our invisible part, which is called the camera anchor.
And we're going to set the key frame of our camera equal to the key frame of our bus.
Afterwards, we're going to have to wait for a little bit of time before we start tweening our bus along
the route that we want it to go.
So because we are delaying between each message for four seconds and we have a total of three messages,
we're going to have to wait at least 12 seconds before we actually start moving the bus.
Otherwise, the players aren't going to see it because their screen's covered by a guy.
So we're just going to put a wait statement in here of 12 seconds, and then after that, 12 seconds
are up, we can go ahead and run the tweens for moving the bus.
So I'm going to create the first tween for the bus, which will move it to the first position.
So tween service we're going to create on our bus dot primary part.
And this is the part that everything in our bus is welded to.
And we could do tween info dot new and we can make the bus drive.
I found that 11 seconds works pretty good, and we can put even a custom enum dot easing style in here
of quad, and this helps to imitate the bus speeding up and then slowing down instead of moving linearly.
And now we want to update the keyframe of our buses primary part equal to.
Inside of the filtering folder.
There is another folder called Bus Goals, and there's two different parts in there that represent the
different keyframes we need to move our bus to.
And this would be bus goal number one.
And we're going to get the keyframe of this part.
And then we're basically just going to copy this again.
But instead we're going to make a second tween.
We'll call it tween number two.
And this time we want to tween our bus two, bus goal number two.
So if we go ahead and look on the map here and let me go to the filtering folder.
Bus goals.
We have bus goal one and bus goal two.
So if we go down here, our first bus goal stops at the entrance of the Krusty Krab.
And then the second bus goal goes all the way to the end of the road.
And at this point, when the bus reaches the second goal, we can basically just destroy it off the
map because we don't need to use it anymore.
So that means we can go ahead and refer to our first tween and then just play it.
Now the problem with this is that our camera is not welded or attached to that camera anchor part in
our bus.
We aren't able to weld our camera to anything, so that means every single frame we're going to have
to update the position of our camera to the position of our camera anchor part.
So that means we're going to have to use our run service and bind a function to the render step event.
So inside of the run service we're going to use the function bind to render step.
We can give it whatever name.
But we're going to call this camera anchor in.
The priority for this is going to be equal to the enum dot render priority dot camera plus one.
This is important that you do plus one because we're going to be moving the camera after the camera
has been updated.
So that way it doesn't look weird or we're not getting any jittering problems when we're trying to move
the camera, because if we made the render priority before the camera, then we're going to be moving
the see frame of our camera to a parts position.
That may not be correct, so we're going to do it after the camera has been updated.
And then we can go ahead and pass the function we wish to bind to render stepped.
And what we're going to do in here is we're just going to refer to our current camera, and we're going
to set the key frame equal to the camera anchor key frame.
However, if we just did bus dot camera anchor dot key frame and we just set our camera key frame to
the buses key frame every single time, then it's going to look all kind of weird and jittery.
And I'm going to show you what I mean.
So remember inside of our game service, when the game starts, we're going to tell all of the clients
to start the intro scene.
And actually we don't need to pass the bus object itself.
I mean, you can do this from the server, but the more I think about it, I think it's just better
if we just pass the action instead and have the clients refer to the bus on their end.
That way we don't have to pass any extra unnecessary information.
But basically we're going to tell all the players to start the intro scene.
And that's basically what's going to call this function right here.
So that means if we go and play test our game.
We should see that.
Okay, we're getting our intro messages.
And the sound is playing for them as well, which is nice.
And now we have attached to the camera.
But it looks like we did get an error attempt to perform arithmetic add on enum item and number I.
And that's because we accidentally forgot to refer to the value of this render priority.
So inside of the camera's render priority, we need to refer to the value stored in this enum instead
of the enum itself.
So that way we're getting the number and then adding one to it.
So that's a quick error we just fixed.
Let's go ahead and try this out again.
All right.
And now, as you see, our camera is following our bus.
But the problem with this is that our bus looks like it's moving a little bit with some jitter to it,
and that jitter can be a little unpleasant.
So the way we can fix this jitter.
Is that inside of our game seeing function, when we're setting the camera, see frame equal to the
see frame of our camera anchor, what we can do instead is we can refer to the current camera, see
frame, and we can use the lerp function or the linear interpolation function to move it to the bus
dot camera anchor dot see frame.
But we're going to pass an alpha value dependent on the delta time that gets passed to our lambda function.
And again, this delta time is going to tell us how much time was passed or what's the delay between
frames.
And using this delay you could actually also calculate the frame rate of your game.
So if you divided one by the delta time it's going to give you the frame rate.
So if we were running at 60 frames per second, that means the delta time or the time between frames
is about 0.016 seconds.
So for the alpha value, what we're going to do is we're going to pass our delta time.
And then we're going to multiply this delta time by a particular number.
And most people that I've seen in scripting call this number a smoothing value.
So we can create a variable outside of here.
And we can call it smoothing.
And we can set it to a number like 60 to represent the default amount of frames that Roblox runs in,
which is 60 frames per second.
So this will help our camera linearly interpolate to the bus's C frame.
But each time we're not moving all the way to this new C frame because we're multiplying it by the delta
time and the smoothing value.
So in every instance when our delta time changes, either due to increases in frame rate or lag spikes,
that causes drops in frame rate, we should reduce the problem of where the camera movement on the bus
looks jittery, and to confirm this we can go ahead and test this out again.
All right.
As you can see, our bus is no longer jittering and our camera movement has improved considerably.
As you can tell, it's no longer jittery.
The bus isn't moving weirdly, and our camera isn't jittering around either.
We now have a nice smooth tween basically of our camera all the way along this bus ride.
Now you can go ahead and mess with the smoothing value all you like, but I found that a value of 60
works pretty well in most cases.
Now, to further add to the ambience of our game, we also want to make sure that the bus sounds like
it's running.
So we want to enable like an engine sound in our bus.
And thankfully inside of our bus and inside of the body of the bus, there is a sound called engine
and this is going to imitate when the bus is driving.
So if we actually go into the workspace and we go to our bus and we go to the body of the bus, here's
our engine sound and I'll just play it here.
This sound just helps to make it sound like, you know, our bus is actually driving.
And then what we're going to do is we're going to refer to our first tween, and we're going to wait
for it to complete.
Because after it completes, then what we could do is we could unbind this function, our camera anchor
function, from the render step, because we don't need the camera to continually follow the camera
anchor part in our bus.
So inside the run service there's a function unbind from render step, and all we need to pass is the
name of this particular function, which was camera anchor.
And then what we're going to do is we're going to make it sound like the bus is now idling, because
it has stopped to drop all of our players off.
So what we're going to do is we're going to create a new tween using our tween service on our bus dot
body dot engine sound.
We're going to use tween info dot new.
We can tween it for like something like 0.8 seconds.
And the thing we want to change inside of the sound instance is the playback speed.
And this will help to make the engine sound like it's idling down or not spinning as fast anymore.
So inside of each sound instance we have a playback speed property.
So normally it sounds like this.
But if I were to decrease this number to something like 0.6, as you can see now, it sounds like our
bus is idling instead of driving.
So we can go ahead and play this tween.
And then inside of the bus dot body, there's another sound called door and we're going to play the
sound to make it, you know, sound like the door of the bus is opening.
So I'll play it real quick for you.
Okay, there we go.
The door of our bus open, and once the door of our bus opens, um, we're going to actually just wait
for two seconds.
And then we're going to get our local player.
We're going to refer to the local player's character.
Get our humanoid root part.
And we're going to set the keyframe of our humanoid root part equal to a part.
Keyframe in the workspace.
So we have another part inside of our filtering folder, and it's inside of our teleport parts folder,
and it's called Bus Stop.
So this is the position that we want the players to move their position to.
And then what we're going to do is we're going to basically just randomly position all of the players,
uh, around here on this platform.
So that way they don't all pile up at the same spot.
So basically what we're going to do is we're going to refer to the filtering folder inside of there.
We're going to get the teleport parts folder and then refer to the bus stop part and get that keyframe.
And then we're going to add an offset to the keyframe by using vector three.
That way we are offsetting in the global axes of our game, and we're just going to create a new vector
three, and we're going to use our RNG next integer to move the player anywhere between, let's say
negative four and four studs on the x axis.
So that means when our players spawn here, they will randomly move anywhere from over here or over
here.
Or we could also move them positively over here or over here.
And actually we could also reposition this part slightly to be more in the center of our, uh, platform
here or this walkway.
So we will basically set the player keyframe to here, and then we're just going to offset it.
So each player will spawn randomly either on this side maybe over here, over here, back here or whatever.
We just don't want them all to teleport themselves to the exact same position.
So we'll move them randomly.
Negative four to positive four studs on the x axis.
We do not have to worry about the y axis.
And then we're going to do the same thing on the z axis.
We could do -4 to 4.
And then after that, since the player's camera is still going to be attached to our camera anchor part,
or basically we still have it in the scriptable mode and the player's camera is going to be stuck sitting
there.
We need to tween the player's camera back to their character.
So what we could do is we could create a tween on the camera.
I'll call it cam tween.
So tween service create on our current camera.
We could do a tween info of like one second and we could do a different enemies style like sine just
to make it a little more fancy.
And we're going to set the keyframe of our camera.
Equal to the local player dot character.
And we could get something like their head and get the C frame of the player's head.
So basically we're just moving the camera to the player's head.
And then we're going to wait for this camera twin to finish.
So Dot completed.
Wait.
And then we're basically just going to reset the current camera's camera type equal to enum dot camera
type dot custom, which will allow the default course scripts for controlling the camera to take back
over.
So if we go ahead and test what we have gotten done so far.
So as you can see, our bus is driving, we're going down along the road and eventually we should slow
down here.
And as you can see, our bus is slowing down until we reach our bus stop point.
There we go.
Our bus idles down.
The door opens.
And any second now our camera should snap back to our player.
But it doesn't look like that's happening.
Probably because we forgot to play our camera team.
Yeah, that's the issue.
So, uh, before we yield, we actually have to make sure that we play the camera tween first.
Okay.
My bad.
Let's go ahead and try this out again.
Our bus is driving down the road, it slows down here and then our camera should tween back to our player.
There we go.
And now we have spawned here and we're ready to enter into our restaurant.
The next things we need to do is we need to restrict our camera to be first person only, and we need
to continue twinning the bus to its opposite position on the other end of this road.
So let's go ahead and do that as well.
So after our camera twin completes, what we're going to do is we're going to refer to our local player.
We're going to get the camera mode property, and we're going to set this to the enum dot camera mode,
dot lock first person.
And then we can set the local player camera max zoom distance equal to 0.5, which basically stops them
from zooming out and they will forever be stuck in first person mode.
Then we can set the camera type back to custom, and then after that's done, we can do something like
wait another two seconds so the bus doesn't immediately leave, and then after those two seconds we're
going to play our second tween.
So our bus drives away from us, and that means we're going to have to override our sound tween that
we created earlier.
So we're going to have to copy this here.
And we're going to create a new tween again on the engine sound.
And instead we're going to set the playback speed back to one.
And then we're going to wait for tween number two to complete.
And then once it has been completed then we're going to basically just destroy our bus because we don't
need it any longer.
And I believe that's our entire start intro scene complete.
So let's go ahead and see what we've got done so far.
Here we are.
We got 11:00.
We should get our next message on a bus to the Krusty Krab for your first shift.
We'll get our third message, and then we should get our camera set to the bus.
Here we go.
We're driving down the road.
We're going to the Krusty Krab.
We also see our objectives shown up here as well.
So we got to earn $500 to pay for rent, and we got to enter the Krusty Krab.
We get our camera tween back to our player.
And as you can see, we're stuck in first person now.
Our bus drives away and eventually it should get destroyed down there.
Perfect.
So we've got all of the introduction stuff done for our game.
I think the next thing we need to do for our game is actually script, the module script that's going
to handle opening and closing all of the doors in our game, because right now we are unfortunately
not able to get into the restaurant.
All right.
So that's all I have for you in this lecture.
And in the next lecture we're going to go ahead and start working on our door system.
So I'll go ahead and see you there.